package com.fourtwenty.hemptress.plugin.wolframalpha;

import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fourtwenty.hemptress.BotResponse;
import com.fourtwenty.hemptress.plugin.annotate.Plugin;
import com.fourtwenty.hemptress.plugin.annotate.Property;
import com.fourtwenty.hemptress.plugin.annotate.events.OnCommand;
import com.fourtwenty.hemptress.plugin.annotate.parameters.Channel;
import com.fourtwenty.hemptress.plugin.annotate.parameters.Params;
import com.fourtwenty.hemptress.plugin.annotate.parameters.SenderNick;
import com.wolfram.alpha.WAEngine;
import com.wolfram.alpha.WAException;
import com.wolfram.alpha.WAPlainText;
import com.wolfram.alpha.WAPod;
import com.wolfram.alpha.WAQuery;
import com.wolfram.alpha.WAQueryResult;
import com.wolfram.alpha.WASubpod;

@Plugin
public class WolframAlpha {
	private static final Logger LOG = LoggerFactory.getLogger(WolframAlpha.class);
	
	private String alphaAppID = "";
	private int alphaLineLimit = 2;
	
	private List<String> alphaRequest(String query) {
		List<String> resultLines = new ArrayList<String>();
		
		WAEngine engine = new WAEngine();
		engine.setAppID(alphaAppID);
		engine.addFormat("plaintext");
		
		WAQuery alphaQ = engine.createQuery(query);
		
		try {
			WAQueryResult result = engine.performQuery(alphaQ);
			
			if(result.isError()) {
				resultLines.add(
						new StringBuilder("Error from W|A: ")
							.append("[code=")
							.append(result.getErrorCode())
							.append(",message=")
							.append(result.getErrorMessage())
							.append("]")
							.toString());
			} else if (!result.isSuccess()) {
				resultLines.add("No results from W|A");
			} else {
				for(WAPod pod : result.getPods()) {
					if(!pod.isError()) {
						for(WASubpod sub : pod.getSubpods()) {
							for(Object ele : sub.getContents()) {
								if(ele instanceof WAPlainText) {
									String[] lines = ((WAPlainText) ele).getText().split("\\r?\\n");
									
									List<String> temp = new ArrayList<>();
									for(String line : lines) {
										String t = 
												line
													.replaceAll("\\|\\s+\\|", " | ")
													.replaceAll("\\s+\\|\\s*$", "")
													.replaceAll("^\\s\\|\\s*", "") 
													.replaceAll("\\s", " ") //normalize spaces
													.trim(); // more whitespace
										
										if(!t.isEmpty()) {
											temp.add(t);
										}
									}
									resultLines.addAll(temp);
								}
							}
						}
					}
				}
			}
		} catch (WAException e) {
			LOG.error("Alpha exception", e);
		}
		
		return resultLines;
	}
	
	@OnCommand({"alpha", "wa", "wolframalpha", "wolfram|alpha"})
	public List<BotResponse> alphaCommand(@Params String query, @SenderNick String nick, @Channel String channel) {
		List<BotResponse> results = new ArrayList<>();
		
		List<String> resultLines = alphaRequest(query);
		BotResponse intro = new BotResponse();
		intro.setTarget(channel);
		intro.setResponse("Sending up to 25 lines in private, first two lines of results: ");
		results.add(intro);
		
		for(int i = 0; i < resultLines.size() - 1 && i < 25; i++) {
			BotResponse br = new BotResponse();
			br.setResponse(resultLines.get(i+1));
			br.setTarget(nick);
			
			if(i < alphaLineLimit) {
				BotResponse br2 = new BotResponse();
				br2.setResponse(resultLines.get(1+i));
				br2.setTarget(channel);
				results.add(br2);
			}
			
			results.add(br);
		}
		
		return results;
	}

	public String getAlphaAppID() {
		return alphaAppID;
	}

	@Property("alpha.appid")
	public void setAlphaAppID(String alphaAppID) {
		this.alphaAppID = alphaAppID;
	}

	public int getAlphaLineLimit() {
		return alphaLineLimit;
	}

	@Property("alpha.channel.limit")
	public void setAlphaLineLimit(String alphaLineLimit) {
		try { 
			setAlphaLineLimit(Integer.parseInt(alphaLineLimit));
		} catch(NumberFormatException e) {
			//do nothing
		}
	}
	
	
	public void setAlphaLineLimit(int alphaLineLimit) {
		this.alphaLineLimit = alphaLineLimit;
	}

}
